import win32api
import win32con

from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.common.action_chains import ActionChains

from common.decorators import log4gs
from common.functions import get_xpath, has_text_wait


@log4gs
class VueRegion(object):
    """
    通过全局搜索类名是ivu-cascader-menu的元素，获取区域
    区域选择器源码结构：
    <span>
        <ul class="ivu-cascader-menu">
            <li>省级名称</li>
            ...
        </ul>
        <span>
            <ul class="ivu-cascader-menu">
                <li>市级名称</li>
                ...
            </ul>
            <span>
                <ul class="ivu-cascader-menu">
                    <li>区级名称</li>
                    ...
                </ul>
            </span>
                ...
        </span>
    </span>
    """

    regionClassName = 'ivu-cascader-menu'

    def __init__(self, index=None, region_level=3, describe=None):
        """
        :param index: 目标元素的序号，获取序号方法：
                通过在浏览器终端执行document.getElementsByClassName('ivu-cascader-menu')
        :param region_level: 区域选择器可以选到的层级，默认三级，即省市区
        :param describe: 描述

        使用方法：
            region = VueRegion(index=0, region_level=5)   # 当前页第一个区域选择器，且有5个区域层级
        """
        if not isinstance(index, int):
            try:
                raise TypeError("必须提供区域选择器的序号")
            except TypeError:
                self.log.error("必须提供区域选择器的序号", exc_info=True)

        self.init_index = index
        self.level = region_level
        self.describe = describe

    def __get__(self, instance, owner):
        self.driver = instance.driver
        try:
            self.init_ul_menu = self.driver.find_elements_by_class_name(self.regionClassName)[self.init_index]
        except Exception:
            self.log.error("通过序号‘{}’没有找到区域选择器".format(self.init_index))
        return self

    def __select(self, menu):
        """通过递归的方式，依次点击给定的区域"""
        if self.__count < self.level:
            all_li = menu.find_elements_by_tag_name('li')
            for i, li in enumerate(all_li):
                li_text = li.text.strip().replace(' ', '')
                if li_text == self.region[self.__count]:
                    li.click()
                    break
                elif i == len(all_li) - 1:
                    try:
                        raise NoSuchElementException("找不到区域：'{}'".format(self.region[self.__count]))
                    except NoSuchElementException:
                        self.log.error("找不到区域：'{}'".format(self.region[self.__count]), exc_info=True)
                elif i < len(all_li) - 1:
                    # 把鼠标移到区域选择列表，然后向下滑动滚轮，让要选择的区域可见
                    action = ActionChains(self.driver)
                    action.move_to_element(li).perform()
                    win32api.mouse_event(win32con.MOUSEEVENTF_WHEEL,0,0,-1)


            self.__count += 1
        else:
            return
        ### 两个相邻menu的xpath规律：
        # /html/body/div[13]/div/span/ul
        # /html/body/div[13]/div/span/span/ul
        if self.__count < self.level:
            menu_xpath = get_xpath(self.driver, menu)
            self.log.info("第{}层级的xpath是：{}".format(self.__count, menu_xpath))
            try:
                next_menu = self.driver.find_element_by_xpath(menu_xpath[:-3] + '/span/ul')
                self.__select(next_menu)
            except Exception:
                self.log.error("获取第{}层级的区域选择器失败".format(self.__count + 1))

    def select(self, region_str):
        """
        :param region_str: 要选择的区域，用-连接上下级，例如：浙江省-杭州市-江干区
        :return:
        """
        self.region = region_str.split('-')
        if '-' not in region_str:
            try:
                raise ValueError("区域字符串'{}'格式错误，需要用'-'连接区域".format(region_str))
            except ValueError:
                self.log.error("区域字符串'{}'格式错误，需要用'-'连接区域".format(region_str), exc_info=True)
        if len(self.region) != self.level:
            try:
                raise ValueError("区域字符串‘{}’与实际区域选择器层级不匹配".format(region_str))
            except ValueError:
                self.log.error("区域字符串‘{}’与实际区域选择器层级不匹配".format(region_str), exc_info=True)

        self.__count = 0
        self.__select(self.init_ul_menu)